﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using KduneeShaders;
using KduneeShaders.PostProcess;

namespace ShaderApp
{
    class VisualState
    {
        public Vector3
            eye = new Vector3(1700, 100, -1500),
            l1p = new Vector3(150+100, 125+100, -15);
        public int exampleIndex = 1;
        public int postEffect = 0;
    }

    public class Engine : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        VisualState state = new VisualState();

        Matrix world2projection;

        ShaderExample[] examples = { new PhongBlinnExample(), new RimExample(), new BumpExample(), new MagicExample(), new UnlitExample(), new WaterExample() };
        PostProcessShader[] postEffects = { new NullPostProcess(), new InvertPostProcess() , new ContrastPostProcess(), new SaturationPostProcess(), new TintPostProcess(), new BlurPostProcessExtended(15)};
        
        Color background = Color.DarkGray;

        public Engine()
        {
            graphics = new GraphicsDeviceManager(this);
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            foreach(ShaderExample ex in examples)
            {
                ex.LoadContent(Content);
            }

            foreach (PostProcessShader sh in postEffects)
            {
                sh.Prepare(graphics, Content);
            }
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            Matrix world2view = Matrix.CreateLookAt(state.eye, Vector3.Zero, Vector3.Up);
            Matrix view2projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
                4 / 3f, 1.0f, 140000.0f);
            world2projection = world2view * view2projection;

            KeyboardState k = Keyboard.GetState();

            if (k.IsKeyDown(Keys.NumPad1)) state.exampleIndex = 0;
            if (k.IsKeyDown(Keys.NumPad2)) state.exampleIndex = 1;
            if (k.IsKeyDown(Keys.NumPad3)) state.exampleIndex = 2;
            if (k.IsKeyDown(Keys.NumPad4)) state.exampleIndex = 3;
            if (k.IsKeyDown(Keys.NumPad5)) state.exampleIndex = 4;
            if (k.IsKeyDown(Keys.NumPad6)) state.exampleIndex = 5;

            if (k.IsKeyDown(Keys.Z)) state.postEffect = 0;
            if (k.IsKeyDown(Keys.X)) state.postEffect = 1;
            if (k.IsKeyDown(Keys.C)) state.postEffect = 2;
            if (k.IsKeyDown(Keys.V)) state.postEffect = 3;
            if (k.IsKeyDown(Keys.B)) state.postEffect = 4;
            if (k.IsKeyDown(Keys.N)) state.postEffect = 5;

            if (k.IsKeyDown(Keys.Home))
            {
                state.l1p.X *= 0.992f;
                state.l1p.Y *= 0.992f;
                state.l1p.Z *= 0.992f;
            }
            else if (k.IsKeyDown(Keys.End))
            {
                state.l1p.X /= 0.992f;
                state.l1p.Y /= 0.992f;
                state.l1p.Z /= 0.992f;
            }

            if (k.IsKeyDown(Keys.OemPlus))
            {
                state.eye *= 0.95f;
            }
            else if (k.IsKeyDown(Keys.OemMinus))
            {
                state.eye /= 0.95f;
            }

            if (k.IsKeyDown(Keys.Left))
            {
                state.eye = Vector3.Transform(state.eye, Matrix.CreateRotationY(0.05f));
            }
            else if (k.IsKeyDown(Keys.Right))
            {
                state.eye = Vector3.Transform(state.eye, Matrix.CreateRotationY(-0.05f));
            }

            if (k.IsKeyDown(Keys.Up))
            {
                state.eye += new Vector3(0, 33.1f, 0);
            }
            else if (k.IsKeyDown(Keys.Down))
            {
                state.eye -= new Vector3(0, 33.1f, 0);
            }

            if (k.IsKeyDown(Keys.Insert))
            {
                background = Color.DarkGray;
            }
            else if (k.IsKeyDown(Keys.Delete))
            {
                background = Color.Black;
            }

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            postEffects[state.postEffect].PreRender(graphics);

            graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, background, 1.0f, 0);

            examples[state.exampleIndex].Draw(gameTime, state.eye, state.l1p, world2projection);

            base.Draw(gameTime);

            postEffects[state.postEffect].PostRender(graphics);
        }
    }
}